﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;

namespace ToolKitIESiteList.Library
{
    public static class HelperEmie
    {
        private const string RootElem = "site-list";
        private const string VersionAttr = "version";
        private const string CreatedByElem = "created-by";
        private const string ToolElem = "tool";
        private const string VersionElem = "version";
        private const string DateCreatedElem = "date-created";
        private const string SiteElem = "site";
        private const string CompatModeElem = "compat-mode";
        private const string OpenInElem = "open-in";
        private const string UrlAttr = "url";
        private const string CommentAttr = "comment";

        [SuppressMessage("Microsoft.Design", "CA1031")]
        [SuppressMessage("Microsoft.Design", "CA1054")]
        public static Uri CreateValidUri(string url)
        {
            Uri urltemp = null;
            if (url.Trim().Length == 0)
            {
                return null;
            }
            var ok = Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out urltemp);
            if (ok)
            {
                try
                {
                    urltemp.GetHostAndPort();
                }
               
               catch 
                {
                    ok = Uri.TryCreate(AddScheme(url), UriKind.RelativeOrAbsolute, out urltemp);
                }
            }
            else
            {
                ok = Uri.TryCreate(AddScheme(url), UriKind.RelativeOrAbsolute, out urltemp);
            }
            try
            {
                urltemp.GetHostAndPort();
            }
            catch
            {
                urltemp = null;
            }
            return urltemp;
        }

        public static string AddScheme(this string str)
        {
            return "http://" + str;
        }

        private static bool HasSpecificPort(this Uri uri)
        {
            return new Regex(string.Format("{0}:\\d+", new object[1]
            {
                uri.Host
            })).IsMatch(uri.OriginalString);
        }

        public static string GetHostAndPort(this Uri uri)
        {
            if (!HasSpecificPort(uri))
                return uri.Host;
            var result = uri.GetComponents(UriComponents.HostAndPort, UriFormat.SafeUnescaped);
            if (uri.HostNameType == UriHostNameType.IPv6)
            {
                if (!uri.OriginalString.Contains(":80"))
                {
                    result = result.Replace(":80", "");
                }
            }
            return result;
        }

        public static string GetUrlAttributeString(this Uri uri)
        {
            string hostAndPort = GetHostAndPort(uri);
            if (uri.AbsolutePath != "/")
                hostAndPort += uri.AbsolutePath;
            return hostAndPort;
        }

        [SuppressMessage("Microsoft.Design", "CA1031")]
        public static void ValidateSchemeSiteList(string fileName)
        {
            var xmlfile = new XmlDocument();
            xmlfile.Load(fileName);

            Assembly a = Assembly.GetExecutingAssembly();
            var stream = a.GetManifestResourceStream("ToolKitIESiteList.Library.Schema.EmieDocumentV2.xsd");
            try
            {
                var schemaSet = new XmlSchemaSet();
                schemaSet.Add(null, new XmlTextReader(stream));

                var settings = new XmlReaderSettings();
                settings.Schemas = schemaSet;
                settings.ValidationType = ValidationType.Schema;

                using (var reader = XmlReader.Create(fileName, settings))
                {
                    while (reader.Read()) ;
                }

            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
        }

        public static void ValidateSchemeSiteDiscovery(string fileName)
        {
            Assembly a = Assembly.GetExecutingAssembly();
            Stream stream = a.GetManifestResourceStream("ToolKitIESiteList.Library.Schema.EmieDiscovery.xsd");
            try
            {
                var schemaSet = new XmlSchemaSet();
                schemaSet.Add(null, new XmlTextReader(stream));

                var settings = new XmlReaderSettings();
                settings.Schemas = schemaSet;
                settings.ValidationType = ValidationType.Schema;

                using (var reader = XmlReader.Create(fileName, settings))
                {
                    while (reader.Read()) ;
                }

            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
        }

        public static XmlNodeList GetAllSites(this XmlDocument xmlDocument)
        {
            if (xmlDocument == null)
                return null;
            return xmlDocument.SelectNodes(string.Format(CultureInfo.InvariantCulture, "/{0}/{1}", RootElem, SiteElem));
        }

        public static string GetVersion(this XmlDocument xmlDocument)
        {
            if (xmlDocument == null)
                return null;
            XmlElement result = null;
            result = xmlDocument.SelectSingleNode(string.Format(CultureInfo.InvariantCulture, "/{0}", RootElem)) as XmlElement;
            return result.GetAttribute(VersionAttr, "");
        }
        public static string GetDateCreated(this XmlDocument xmlDocument)
        {
            if (xmlDocument == null)
                return null;
            var result = xmlDocument.SelectSingleNode(string.Format(CultureInfo.InvariantCulture, "/{0}/{1}/{2}", RootElem, CreatedByElem, DateCreatedElem)) as XmlElement;
            if (result == null)
                return null;
            return GetFirstText(result);
        }
        public static string GetComment(this XmlElement xmlElement)
        {
            return xmlElement.GetAttribute(CommentAttr, "");
        }


        public static string GetFirstText(this XmlElement xmlElement)
        {
            if (xmlElement.FirstChild == null)
                return "";
            return xmlElement.FirstChild.Value.Trim();
        }
        [SuppressMessage("Microsoft.Design", "CA1055")]
        public static string GetUrl(this XmlElement xmlElement)
        {
            return xmlElement.GetAttribute(UrlAttr);
        }
        public static CompatMode GetCompatMode(this XmlElement xmlElement)
        {
            XmlElement result = xmlElement.SelectSingleNode(CompatModeElem) as XmlElement;
            if (result != null)
            {
                string firstText = GetFirstText(result);
                foreach (CompatMode compatMode in Enum.GetValues(typeof(CompatMode)))
                {
                    if (firstText == compatMode.ToString())
                        return compatMode;
                }
            }
            return CompatMode.Default;
        }
        public static OpenIn GetOpenIn(this XmlElement xmlElement)
        {
            XmlElement result = xmlElement.SelectSingleNode(OpenInElem) as XmlElement;
            if (result != null)
            {
                string firstText = GetFirstText(result);
                foreach (OpenIn openIn in Enum.GetValues(typeof(OpenIn)))
                {
                    if (firstText == openIn.ToString())
                        return openIn;
                }
            }
            return OpenIn.None;
        }

        public static void SaveToV2file(IEnumerable<IEModeDataItem> sites, string fileName, string tool, string toolversion, string date, string versionFile)
        {
            var siteEntries = sites.Select(entry => new XElement(SiteElem,
                                new XAttribute(UrlAttr, entry.Url),
                                new XAttribute(CommentAttr, entry.Comment),
                                new XElement(CompatModeElem, entry.CompatMode),
                                new XElement(OpenInElem, entry.OpenIn)));

            XElement siteList = new XElement(
                RootElem,
                new XAttribute(VersionAttr, versionFile));

            if (!string.IsNullOrEmpty(tool))
            {
                var createby = new XElement(CreatedByElem);
                createby.Add(new XElement(ToolElem, tool));
                createby.Add(new XElement(VersionElem, toolversion));
                createby.Add(new XElement(DateCreatedElem, date));
                siteList.Add(createby);
            }
            siteList.Add(siteEntries);
            //Salva o arquivo em disco
            siteList.Save(fileName);
        }


    }
}
